package schuchert.contest;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class ConTestInsrumentationMainBasedClassFileTransformerFilterTest {
    ConTestInstrumentationMainBasedClassFileTransformer transformer;
    private final String filter;
    private final boolean comIbmShouldBeInstrumented;
    private final boolean javaIoShouldBeInstrumented;
    private final boolean schuchertShouldBeInstrumented;
    private final boolean fooShouldBeInstrumented;

    @Before
    public void setup() {
        transformer = new ConTestInstrumentationMainBasedClassFileTransformer();
    }

    @Parameters
    public static Collection<Object[]> data() {
        ArrayList<Object[]> values = new ArrayList<Object[]>();
        values.add(new Object[] { "", true, true, true, true });
        values.add(new Object[] { "-java", true, false, true, true });
        return values;
    }

    public ConTestInsrumentationMainBasedClassFileTransformerFilterTest(String filter,
            boolean matchComIbm, boolean matchJavaIo, boolean matchSchuchert, boolean matchFoo) {
        this.filter = filter;
        this.comIbmShouldBeInstrumented = matchComIbm;
        this.javaIoShouldBeInstrumented = matchJavaIo;
        this.schuchertShouldBeInstrumented = matchSchuchert;
        this.fooShouldBeInstrumented = matchFoo;
    }

    @Test
    public void checkPattern() {
        transformer.setFilter(filter);
        assertFilterMatchedCorrectly("com/ibm", comIbmShouldBeInstrumented);
        assertFilterMatchedCorrectly("java/io", javaIoShouldBeInstrumented);
        assertFilterMatchedCorrectly("schuchert/contest/", schuchertShouldBeInstrumented);
        assertFilterMatchedCorrectly("foo", fooShouldBeInstrumented);
    }

    private void assertFilterMatchedCorrectly(String string, boolean expected) {
        boolean result = transformer.isClassWeShouldProcess(string);
        assertEquals(String.format("Filter: %s, pattern: %s", filter, string), expected, result);

    }

    public void onlyExcludeClassesStartingWithJava() {
        transformer.setFilter("-java");
        assertIsNotFiltered("com/ibm");
        assertIsFiltered("java/io");
        assertIsNotFiltered("schuchert/contest/");
    }

    public void onlyIncludedClassesStartingWithJava() {
        transformer.setFilter("+java");
        assertIsFiltered("com/ibm");
        assertIsNotFiltered("java/io");
        assertIsFiltered("schuchert/contest/");
    }

    public void multipleExclusionsLeaveDefaultRepsonseToTrueIfNoMatchesFound() {
        transformer.setFilter("-java:-com");
        assertIsFiltered("java/io");
        assertIsNotFiltered("schuchert/contest/");
        assertIsFiltered("com/ibm");
    }

    public void oneInclusionCausesEverythingNotMatchingToBeExcluded() {
        transformer.setFilter("+java:-schuchert:-ibm:-com");
        assertIsNotFiltered("java/io");
        assertIsFiltered("schuchert/contest/");
        assertIsFiltered("com/ibm");
        assertIsFiltered("ibm");
        assertIsFiltered("foo");
    }

    private void assertIsNotFiltered(String string) {
        assertTrue(transformer.isClassWeShouldProcess(string));
    }

    private void assertIsFiltered(String string) {
        assertFalse(transformer.isClassWeShouldProcess(string));
    }
}
